home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 June: Reference Library / Dev.CD Jun 96 RL / Dev.CD Jun 96 RL.toast / Technical Documentation / develop / develop Issue 23 / develop Issue 23 code / ProjectDrag 1.1b8 / Sources / ProjectDrag Sources / ProjectAlias.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-11  |  17.0 KB  |  651 lines  |  [TEXT/MPS ]

  1. /* ProjectAlias.c: ProjectorDB alias management routines for ProjectDrag
  2.  *
  3.  * A set of applets for drag and drop source control by Tim Maroney.
  4.  * See develop, issue 23 for details.
  5.  *
  6.  * Built on DropShell by Leonard Rosenthol, Stephan Somogyi, and Marshall Clow,
  7.  * and using the MoreFiles utilities by Jim Luther.
  8.  *
  9.  * This software is free, but don't modify and redistribute it without
  10.  * changing the status window to indicate your name and your changes!
  11.  */
  12.  
  13. #include <Errors.h>
  14. #include <Finder.h>
  15. #include <Resources.h>
  16. #include <Script.h>
  17. #include <TextUtils.h>
  18. #include <LowMem.h>
  19. #include <StandardFile.h>
  20.  
  21. #include "ProjectAlias.h"
  22. #include "SourceServer.h"
  23. #include "MoreFiles.h"
  24. #include "MoreFilesExtras.h"
  25.  
  26.  
  27. typedef struct NameMapping
  28. {
  29.     struct NameMapping *fNext;
  30.     StringPtr fProjectName;
  31.     StringPtr fFolderName;
  32. } NameMapping;
  33.  
  34.  
  35. OSErr FindProjectAliasFromProjectName(StringPtr topProjectName, StringPtr realProjectName,
  36.                                         AliasHandle *aliasOut, Boolean isFolderName);
  37.  
  38.  
  39. /* does the folder have a ProjectorDB? */
  40.     
  41. Boolean IsProjectorFolder(short vRefNum, long folderID)
  42. {
  43.     CInfoPBRec pb;
  44.     OSErr err;
  45.     
  46.     pb.hFileInfo.ioNamePtr = "\pProjectorDB";
  47.     pb.hFileInfo.ioVRefNum = vRefNum;
  48.     pb.hFileInfo.ioDirID = folderID;
  49.     pb.hFileInfo.ioFDirIndex = 0;
  50.     err = PBGetCatInfoSync(&pb);
  51.     if (err != noErr) return false;
  52.     return pb.hFileInfo.ioFlFndrInfo.fdType == 'MPSP';
  53. }
  54.  
  55.  
  56. /* Make an alias for a projector database in the preferences folder
  57.  * so ProjectDrag can deal with the project.
  58.  */
  59.  
  60. OSErr MakeProjectAlias(short vRefNum, long folderID, AliasHandle *aliasOut)
  61. {
  62.     AliasHandle alias = NULL;
  63.     OSErr err = noErr;
  64.     FSSpec aliasFile;
  65.     FSSpec projectFile;
  66.     short resRefNum;
  67.     long testFolderID;
  68.     Boolean verified = false;
  69.     
  70.     if (aliasOut != NULL)
  71.         *aliasOut = NULL;
  72.     
  73.     /* Since people are human, they sometimes drag in non-topmost projects.
  74.      * That's OK. Iterate up to the top-level project. We assume that any
  75.      * folder containg a ProjectorDB is part of a hierarchy, so if the parent
  76.      * contains one, we loop upwards.
  77.      */
  78.     testFolderID = folderID;
  79.     while (IsProjectorFolder(vRefNum, testFolderID))
  80.     {
  81.         CInfoPBRec pb;
  82.         
  83.         /* the previously checked folder was indeed a Projector folder */
  84.         verified = true;
  85.         folderID = testFolderID;
  86.         
  87.         /* get the parent folder for the next test */
  88.         pb.hFileInfo.ioNamePtr = NULL;
  89.         pb.hFileInfo.ioVRefNum = vRefNum;
  90.         pb.hFileInfo.ioDirID = testFolderID;
  91.         pb.hFileInfo.ioFDirIndex = -1;
  92.         err = PBGetCatInfoSync(&pb);
  93.         if (err != noErr) break;
  94.         testFolderID = pb.dirInfo.ioDrParID;
  95.     }
  96.     if (!verified) return fnfErr;
  97.  
  98.     /* get the name of the projector folder */
  99.     err = FindPreferencesFolder(&aliasFile.vRefNum, &aliasFile.parID);
  100.     if (err != noErr) return err;
  101.     err = GetDirName(vRefNum, folderID, aliasFile.name);
  102.     if (err != noErr) return err;
  103.     
  104.     /* make the alias */
  105.     projectFile.vRefNum = vRefNum;
  106.     projectFile.parID = folderID;
  107.     projectFile.name[0] = 0;
  108.     err = NewAlias(NULL, &projectFile, &alias);
  109.     if (err != noErr) return err;
  110.     
  111.     /* make the alias file
  112.      *
  113.      * note -- officially the format of alias files is private. You should only
  114.      * create them by sending a Make Alias Apple Event to the Finder. Maybe in
  115.      * ProjectDrag 1.1. Just don't wave this around and say Apple endorses this
  116.      * practice. It doesn't!
  117.      *
  118.      */
  119.     FSpCreateResFile(&aliasFile, kSourceServerCreator, kSourceServerType, smSystemScript);
  120.     err = ResError();
  121.     if (err == dupFNErr)
  122.     {
  123.         /* alias already exists -- delete it & create new one */
  124.         FSpDelete(&aliasFile);
  125.         FSpCreateResFile(&aliasFile, kSourceServerCreator, kSourceServerType, smSystemScript);
  126.         err = ResError();
  127.     }
  128.     if (err != noErr)
  129.     {
  130.         DisposeHandle((Handle)alias);
  131.         return err;
  132.     }
  133.     
  134.     /* open the alias file */
  135.     resRefNum = FSpOpenResFile(&aliasFile, fsRdWrPerm);
  136.     if (resRefNum < 0)
  137.     {
  138.         err = ResError();
  139.         DisposeHandle((Handle)alias);
  140.         FSpDelete(&aliasFile);
  141.         return err;
  142.     }
  143.     
  144.     /* add the alias resource */
  145.     AddResource((Handle)alias, 'alis', 0, "\p");
  146.     err = ResError();
  147.     if (err != noErr)
  148.     {
  149.         CloseResFile(resRefNum);
  150.         DisposeHandle((Handle)alias);
  151.         FSpDelete(&aliasFile);
  152.         return err;
  153.     }
  154.     if (aliasOut != NULL)
  155.     {
  156.         *aliasOut = alias;
  157.         err = HandToHand((Handle*)aliasOut);
  158.         if (err != noErr)
  159.         {
  160.             CloseResFile(resRefNum);
  161.             *aliasOut = NULL;
  162.             return err;
  163.         }
  164.     }
  165.     CloseResFile(resRefNum);
  166.     
  167.     /* turn it into an alias file, name locked, not yet inited */
  168.     err = FSpChangeFDFlags(&aliasFile, true, kIsAlias | kNameLocked);
  169.     if (err == noErr)
  170.         err = FSpChangeFDFlags(&aliasFile, false, kHasBeenInited);
  171.     if (err != noErr)
  172.     {
  173.         FSpDelete(&aliasFile);
  174.         if (aliasOut != NULL)
  175.         {
  176.             DisposeHandle((Handle)*aliasOut);
  177.             *aliasOut = NULL;
  178.         }
  179.         return err;
  180.     }
  181.     return noErr;
  182. }
  183.  
  184.  
  185. /* see note above -- officially, getting an alias from a file this way is naughty.
  186.  * However, ResolveAliasFile doesn't give any control over the flags to MatchAlias,
  187.  * or even give you the alias handle, on which we call GetAliasInfo. Sorry!
  188.  */
  189.  
  190. OSErr GetAliasFromFile(FSSpec *file, AliasHandle *aliasOut)
  191. {
  192.     short resRefNum;
  193.     AliasHandle alias;
  194.     FSSpec aliasFile;
  195.     
  196.     aliasFile.vRefNum = file->vRefNum;
  197.     aliasFile.parID = file->parID;
  198.     BlockMove(file->name, aliasFile.name, file->name[0] + 1);
  199.     resRefNum = FSpOpenResFile(&aliasFile, fsRdPerm);
  200.     if (resRefNum < 0)
  201.         return ResError();
  202.     alias = (AliasHandle)Get1IndResource('alis', 1);
  203.     if (alias == NULL)
  204.     {
  205.         CloseResFile(resRefNum);
  206.         FSpDelete(&aliasFile); /* bad file -- kill it */
  207.         return resNotFound;
  208.     }
  209.     DetachResource((Handle)alias);
  210.     *aliasOut = alias;
  211.     CloseResFile(resRefNum);
  212.     return noErr;
  213. }
  214.  
  215.  
  216. /* Strip the name of the leading project from a full project name */
  217.  
  218. void GetTopProjectName(StringPtr projectName, StringPtr topProjectName)
  219. {
  220.     StringPtr src = projectName + 1;
  221.     StringPtr dst = topProjectName + 1;
  222.     short len = projectName[0];
  223.     short i;
  224.     
  225.     topProjectName[0] = 0;
  226.     for (i = 0; i < len; i++)
  227.     {
  228.         if (*src == kProjectorPathSeparator)
  229.             break;
  230.         *dst++ = *src++;
  231.         topProjectName[0]++;
  232.     }
  233. }
  234.  
  235.  
  236. /* get a project name from a CKID resource */
  237.  
  238. OSErr FindProjectAliasFromCKID(CKIDHandle theCKID, AliasHandle *aliasOut, StringPtr projectName)
  239. {
  240.     Str31 topProjectName;
  241.     Str31 realProjectName;
  242.  
  243.     /* extract the project name from the CKID */
  244.     BlockMove((*theCKID)->projectPath, projectName, (*theCKID)->projectPath[0] + 1);
  245.     
  246.     /* find the leading project name */
  247.     GetTopProjectName(projectName, topProjectName);
  248.     
  249.     /* now search the preferences folder */
  250.     return FindProjectAliasFromProjectName(topProjectName, realProjectName, aliasOut, false);
  251. }
  252.  
  253.  
  254. void DeleteMapping(NameMapping *theMapping)
  255. {
  256.     while (theMapping != NULL)
  257.     {
  258.         NameMapping *aMapping = theMapping->fNext;
  259.         if (theMapping->fProjectName != NULL)
  260.             DisposePtr((Ptr)theMapping->fProjectName);
  261.         if (theMapping->fFolderName != NULL)
  262.             DisposePtr((Ptr)theMapping->fFolderName);
  263.         theMapping = aMapping;
  264.         DisposePtr((Ptr)theMapping);
  265.     }
  266. }
  267.  
  268.  
  269. OSErr AddNameMapping(StringPtr folderName, StringPtr projectName)
  270. {
  271.     OSErr err;
  272.     FSSpec file;
  273.     Handle fileData = NULL;
  274.     short refNum = -1;
  275.     char c;
  276.     
  277.     /* find the preferences folder */
  278.     err = FindPreferencesFolder(&file.vRefNum, &file.parID);
  279.     if (err != noErr) goto ErrorExit;
  280.     
  281.     /* get the Folder Names file data */
  282.     GetIndString(file.name, kProjectDragStrings, kNameMappingFile);
  283.     err = GetFileData(&file, &fileData, &refNum);
  284.     if (err == fnfErr)
  285.     {
  286.         /* create and open the file */
  287.         err = FSpCreate(&file, 'MPS ', 'TEXT', smSystemScript);
  288.         if (err != noErr) goto ErrorExit;
  289.         err = FSpOpenDF(&file, fsRdWrPerm, &refNum);
  290.         if (err != noErr) goto ErrorExit;
  291.         fileData = TempNewHandle(0, &err);
  292.     }
  293.     if (err != noErr) goto ErrorExit;
  294.     
  295.     /* add a line containing the new mapping -- XXX -- assumes EOL at EOF */
  296.     err = PtrAndHand(projectName + 1, fileData, projectName[0]);
  297.     if (err != noErr) goto ErrorExit;
  298.     c = '=';
  299.     err = PtrAndHand(&c, fileData, 1);
  300.     if (err != noErr) goto ErrorExit;
  301.     err = PtrAndHand(folderName + 1, fileData, folderName[0]);
  302.     if (err != noErr) goto ErrorExit;
  303.     c = '\n';
  304.     err = PtrAndHand(&c, fileData, 1);
  305.     if (err != noErr) goto ErrorExit;
  306.     err = WriteFileWithHeader(refNum, fileData, 0, NULL);
  307.     if (err != noErr) goto ErrorExit;
  308.     
  309.     /* clean up and go */
  310.     DisposeHandle(fileData);
  311.     FSClose(refNum);
  312.     return noErr;
  313.  
  314. ErrorExit:
  315.     if (fileData != NULL)
  316.         DisposeHandle(fileData);
  317.     if (refNum != -1)
  318.         FSClose(refNum);
  319.     return err;
  320. }
  321.  
  322. /* Some individuals have decided to name their checkout folder something different
  323.  * from their project name. For this reason we keep a file called "Folder Names".
  324.  * This is a text file with lines of the form (e.g.) "InfoAccessProj=InfoAccess",
  325.  * where the project name is first and the folder name second.
  326.  */
  327.  
  328. NameMapping *GetNameMapping(void)
  329. {
  330.     OSErr err;
  331.     FSSpec file;
  332.     Handle fileData;
  333.     short refNum;
  334.     StringPtr fileLine;
  335.     long fileLength;
  336.     long fileLineLength;
  337.     NameMapping *theMapping = NULL;
  338.     
  339.     /* find the preferences folder */
  340.     err = FindPreferencesFolder(&file.vRefNum, &file.parID);
  341.     if (err != noErr) return NULL;
  342.     
  343.     /* get the Folder Names file data */
  344.     GetIndString(file.name, kProjectDragStrings, kNameMappingFile);
  345.     err = GetFileData(&file, &fileData, &refNum);
  346.     if (err != noErr) return NULL;
  347.     FSClose(refNum);
  348.     
  349.     /* parse the strings */
  350.     HLock(fileData);
  351.     fileLength = GetHandleSize(fileData);
  352.     fileLine = *fileData;
  353.     fileLineLength = LineSize(fileLine, fileLength);
  354.     do
  355.     {
  356.         short equalSign;
  357.         short partLength;
  358.         
  359.         /* find the equal sign */
  360.         for (equalSign = 0;
  361.              equalSign < fileLineLength && fileLine[equalSign] != '=';
  362.              equalSign++)
  363.                 ;
  364.         if (equalSign < fileLineLength)
  365.         {
  366.             /* allocate the mapping struct */
  367.             NameMapping *aMapping = (NameMapping*)NewPtrClear(sizeof(NameMapping));
  368.             if (aMapping == NULL)
  369.             {
  370.                 DisposeHandle(fileData);
  371.                 DeleteMapping(theMapping);
  372.                 return NULL;
  373.             }
  374.             
  375.             /* extract the line up to the equal sign */
  376.             partLength = equalSign;
  377.             aMapping->fProjectName = NewPtr(partLength + 1);
  378.             if (aMapping->fProjectName == NULL)
  379.             {
  380.                 DisposePtr((Ptr)aMapping);
  381.                 DisposeHandle(fileData);
  382.                 DeleteMapping(theMapping);
  383.                 return NULL;
  384.             }
  385.             BlockMoveData(fileLine, aMapping->fProjectName + 1, partLength);
  386.             aMapping->fProjectName[0] = partLength;
  387.             
  388.             /* extract the line after the equal sign -- XXX -- assumes EOL at EOF.... */
  389.             partLength = (fileLineLength - equalSign) - 2;
  390.             aMapping->fFolderName = NewPtr(partLength);
  391.             if (aMapping->fFolderName == NULL)
  392.             {
  393.                 DisposePtr((Ptr)aMapping->fProjectName);
  394.                 DisposePtr((Ptr)aMapping);
  395.                 DisposeHandle(fileData);
  396.                 DeleteMapping(theMapping);
  397.                 return NULL;
  398.             }
  399.             BlockMoveData(fileLine + equalSign + 1, aMapping->fFolderName + 1, partLength);
  400.             aMapping->fFolderName[0] = partLength;
  401.             
  402.             /* link this mapping into the list */
  403.             aMapping->fNext = theMapping;
  404.             theMapping = aMapping;
  405.         }
  406.         
  407.         /* next line */
  408.         fileLine += fileLineLength;
  409.         fileLength -= fileLineLength;
  410.         fileLineLength = LineSize(fileLine, fileLength);
  411.     } while (fileLength > 0);
  412.     
  413.     DisposeHandle(fileData);
  414.     return theMapping;
  415. }
  416.  
  417.  
  418. /* Find the alias to the ProjectorDB based on the name of the project. */
  419.  
  420. OSErr FindProjectAliasFromProjectName(StringPtr topProjectName, StringPtr realProjectName,
  421.                                         AliasHandle *aliasOut, Boolean isFolderName)
  422. {
  423.     CInfoPBRec pb;
  424.     OSErr err = noErr;
  425.     short vRefNum;
  426.     long folderID;
  427.     
  428.     /* default real name is the name passed in */
  429.     BlockMoveData(topProjectName, realProjectName, topProjectName[0] + 1);
  430.     
  431.     /* check for folder name mapping */
  432.     if (isFolderName)
  433.     {
  434.         NameMapping *theMapping = GetNameMapping();
  435.         if (theMapping != NULL)
  436.         {
  437.             NameMapping *aMapping;
  438.             for (aMapping = theMapping; aMapping != NULL; aMapping = aMapping->fNext)
  439.             {
  440.                 if (EqualString(topProjectName, aMapping->fFolderName, false, false))
  441.                 {
  442.                     BlockMoveData(aMapping->fProjectName, realProjectName, aMapping->fProjectName[0] + 1);
  443.                     break;
  444.                 }
  445.             }
  446.             DeleteMapping(theMapping);
  447.         }
  448.     }
  449.     
  450.     /* find the preferences folder */
  451.     err = FindPreferencesFolder(&vRefNum, &folderID);
  452.     if (err != noErr) return err;
  453.  
  454.     /* loop over the aliases in the preferences folder */
  455.     for (pb.hFileInfo.ioFDirIndex = 1, err = noErr; err == noErr; pb.hFileInfo.ioFDirIndex++)
  456.     {
  457.         Str31 fileName;
  458.         fileName[0] = 0;
  459.         pb.hFileInfo.ioNamePtr = fileName;
  460.         pb.hFileInfo.ioVRefNum = vRefNum;
  461.         pb.hFileInfo.ioDirID = folderID;
  462.         err = PBGetCatInfoSync(&pb);
  463.         if (err == noErr && (pb.hFileInfo.ioFlAttrib & 0x10) == 0 && (pb.hFileInfo.ioFlFndrInfo.fdFlags & kIsAlias))
  464.         {
  465.             /* does the alias file name match the project name? */
  466.             if (EqualString(realProjectName, fileName, false, false))
  467.             {
  468.                 /* found it! now extract the alias handle */
  469.                 FSSpec file;
  470.                 file.vRefNum = vRefNum;
  471.                 file.parID = folderID;
  472.                 BlockMove(fileName, file.name, fileName[0] + 1);
  473.                 err = GetAliasFromFile(&file, aliasOut);
  474.                 return err;
  475.             }
  476.         }
  477.     }
  478.     
  479.     return fnfErr; /* file not found error */
  480. }
  481.  
  482.  
  483. /* find the alias to a ProjectorDB based on a checkout folder */
  484.  
  485. OSErr FindProjectAliasFromFolder(short vRefNum, long folderID, AliasHandle *aliasOut, StringPtr projectName)
  486. {
  487.     CInfoPBRec pb;
  488.     Str31 fileName;
  489.     Str31 realProjectName;
  490.     OSErr err = noErr;
  491.     unsigned char sep[2];
  492.  
  493.     if (folderID == fsRtDirID || folderID == fsRtParID)
  494.         return fnfErr; /* end of recursion */
  495.  
  496.     /* look for projector files in this folder; use one of them... */    
  497.     for (pb.hFileInfo.ioFDirIndex = 1; err == noErr; pb.hFileInfo.ioFDirIndex++)
  498.     {
  499.         fileName[0] = 0;
  500.         pb.hFileInfo.ioNamePtr = fileName;
  501.         pb.hFileInfo.ioVRefNum = vRefNum;
  502.         pb.hFileInfo.ioDirID = folderID;
  503.         err = PBGetCatInfoSync(&pb);
  504.         if (err == noErr && (pb.hFileInfo.ioFlAttrib & 0x10) == 0 && pb.hFileInfo.ioFlRLgLen > 0)
  505.         {
  506.             /* it's a file and it has a resource fork -- get the CKID */
  507.             CKIDHandle theCKID;
  508.             FSSpec file;
  509.             
  510.             file.vRefNum = vRefNum;
  511.             file.parID = folderID;
  512.             BlockMove(fileName, file.name, fileName[0] + 1);
  513.             err = ExtractCKID(&file, &theCKID);
  514.             if (err == noErr)
  515.             {
  516.                 err = FindProjectAliasFromCKID(theCKID, aliasOut, projectName);
  517.                 DisposeHandle((Handle)theCKID);
  518.                 if (err == noErr)
  519.                     return noErr;
  520.             }
  521.         }
  522.     }
  523.     
  524.     /* that didn't work -- now try walking up the folders */
  525.     
  526.     /* set up the initial project name */
  527.     sep[0] = 1;
  528.     sep[1] = kProjectorPathSeparator;
  529.     
  530.     /* find the name of the folder specified in the arguments */
  531.     fileName[0] = 0;
  532.     pb.hFileInfo.ioNamePtr = fileName;
  533.     pb.hFileInfo.ioVRefNum = vRefNum;
  534.     pb.hFileInfo.ioDirID = folderID;
  535.     pb.hFileInfo.ioFDirIndex = -1;
  536.     err = PBGetCatInfoSync(&pb);
  537.     if (err != noErr)
  538.         return err;
  539.     
  540.     /* see if the argument folder is the project */
  541.     err = FindProjectAliasFromProjectName(fileName, realProjectName, aliasOut, true);
  542.     if (err == noErr)
  543.     {
  544.         projectName[0] = 0;
  545.         AppendString(projectName, realProjectName);
  546.         AppendString(projectName, sep);
  547.         return noErr;
  548.     }
  549.     
  550.     /* recurse upwards looking for a project */
  551.     if (pb.dirInfo.ioDrParID != fsRtDirID && pb.dirInfo.ioDrParID != fsRtParID)
  552.     {
  553.         err = FindProjectAliasFromFolder(vRefNum, pb.dirInfo.ioDrParID, aliasOut, projectName);
  554.         if (err == noErr)
  555.         {
  556.             AppendString(projectName, fileName);
  557.             AppendString(projectName, sep);
  558.             return noErr;
  559.         }
  560.     }
  561.     
  562.     return fnfErr; /* file not found error */
  563. }
  564.  
  565.  
  566. /* Given an alias to a ProjectorDB, mount it. */
  567.  
  568. OSErr MountProjectAlias(AliasHandle alias, CStringHandle *output, CStringHandle *diagnostic)
  569. {
  570.     OSErr err;
  571.     short aliasCount = 1;
  572.     FSSpec projectFile;
  573.     Boolean needsUpdate;
  574.     AEDesc command;
  575.     
  576.     *output = *diagnostic = NULL;
  577.     
  578.     /* resolve the alias to auto-mount the server */
  579.     err = MatchAlias (NULL, kARMSearch + kARMMountVol, alias, &aliasCount, &projectFile, &needsUpdate, NULL, NULL);
  580.     if (err != noErr)
  581.         return err;
  582.     
  583.     /* is this project already mounted?
  584.      * ProjectInfo -only -project <projectName>
  585.      */
  586.     err = CreateCommand(&command, "ProjectInfo");
  587.     if (err == noErr)
  588.     {
  589.         Boolean alreadyMounted = false;
  590.         err = AddCStringArg(&command, "-only");
  591.         if (err == noErr)
  592.         {
  593.             err = AddProjectArg(&command, projectFile.name);
  594.             if (err == noErr)
  595.             {
  596.                 err = SourceServerCommand(&command, output, diagnostic, ProjectDragIdleProc, NULL);
  597.                 alreadyMounted = (err == noErr);
  598.                 if (*output != NULL)
  599.                     DisposeHandle((Handle)*output);
  600.                 if (*diagnostic != NULL)
  601.                     DisposeHandle((Handle)*diagnostic);
  602.                 *output = *diagnostic = NULL;
  603.             }
  604.         }
  605.         AEDisposeDesc(&command);
  606.         if (alreadyMounted)
  607.             return noErr;
  608.         else if (err < noErr) /* not mounted returns a positive error status (2) */
  609.             return err;
  610.     }
  611.     
  612.     /* send the MountProject command */
  613.     err = CreateCommand(&command, "MountProject");
  614.     if (err == noErr)
  615.     {
  616.         err = AddFileNameArg(&command, &projectFile);
  617.         if (err == noErr)
  618.             err = SourceServerCommand(&command, output, diagnostic, ProjectDragIdleProc, NULL);
  619.         AEDisposeDesc(&command);
  620.     }
  621.     return err;
  622. }
  623.  
  624.  
  625. Boolean SelectProjectorDB(FSSpec *file, short strListID, short strIndex,
  626.                             FileFilterYDProcPtr filter, void *dataPtr)
  627. {
  628.     OSType theType = 'MPSP';
  629.     StandardFileReply reply;
  630.     Str255 prompt;
  631.     Point where;
  632.     short vRefNum;
  633.     long folderID;
  634.     OSErr err;
  635.     
  636.     err = FindPreferencesFolder(&vRefNum, &folderID);
  637.     if (err == noErr)
  638.     {
  639.         LMSetSFSaveDisk(-vRefNum);
  640.         LMSetCurDirStore(folderID);
  641.     }
  642.     SetPt(&where, -1, -1);
  643.     GetIndString(prompt, strListID, strIndex);
  644.     ParamText(prompt, NULL, NULL, NULL);
  645.     CustomGetFile (filter, 1, &theType, &reply, kSelectWithPromptDialog, where,
  646.                     NULL, NULL, NULL, NULL, dataPtr);
  647.     if (reply.sfGood)
  648.         *file = reply.sfFile;
  649.     return reply.sfGood;
  650. }
  651.